#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <sys/times.h>
#include <math.h>


/* Prototipos de las funciones */
void hijo_tratamiento_senal(int signum);
void padre_tratamiento_senal(int signum);
void bloquearSenal(sigset_t *oldSet);
void desbloquearSenal(sigset_t *oldSet);

/* Varaibles globales */
int pid;
sigset_t sigs;
struct sigaction sa_old;
struct sigaction sa_new;
int estado; /*estado del proceso*/
struct tms bt1, bt2;
clock_t t1, t2;
int flag_bloq_desploq = 0; /*Flag que indica si todas las señales están bloqueadas o no*/

int main(int argc, char *argv[])
{

	t1 = times(&bt1);
	
	pid = fork();
	if(pid == -1)
	{
		/* Error en la creación del proceso hijo */
		perror("Error en la creación del proceso hijo.");
		exit(-1);
	}
	else if(pid == 0)
	{
		/* Proceso hijo */
		printf("Soy hijo, mi pid = %d \n",getpid());
		sa_new.sa_handler = hijo_tratamiento_senal;
		
		
		/* Señales a bloquear */
		sigemptyset(&sa_new.sa_mask);
		sigaddset(&sa_new.sa_mask,SIGUSR1);
		sigaddset(&sa_new.sa_mask,SIGUSR2);
		sa_new.sa_flags = 0;
		
		sigaction(SIGUSR1,&sa_new,&sa_old);
		sigaction(SIGUSR2,&sa_new,&sa_old);
		
		sigfillset(&sigs);
		sigdelset(&sigs,SIGUSR1);
		sigdelset(&sigs,SIGUSR2);
		
		/* Esperar las señales */
		while(1)
		{
			sigsuspend(&sigs);
		}
	}
	else
	{
		/* Proceso padre */
		printf("Soy padre, mi pid = %d \n",getpid());
		sa_new.sa_handler = padre_tratamiento_senal;
		
		
		/* Señales a bloquear */
		sigemptyset(&sa_new.sa_mask);
		sigaddset(&sa_new.sa_mask,SIGUSR1);
		sigaddset(&sa_new.sa_mask,SIGINT);
		sigaddset(&sa_new.sa_mask,SIGALRM);
		sigaddset(&sa_new.sa_mask,SIGCHLD);
		sa_new.sa_flags = 0;
		
		sigaction(SIGUSR1,&sa_new,&sa_old);
		sigaction(SIGINT,&sa_new,&sa_old);
		sigaction(SIGALRM,&sa_new,&sa_old);
		sigaction(SIGCHLD,&sa_new,&sa_old);
		
		sigfillset(&sigs);
		sigdelset(&sigs,SIGUSR1);
		sigdelset(&sigs,SIGINT);
		sigdelset(&sigs,SIGALRM);
		sigdelset(&sigs,SIGCHLD);
		
		while(1)
		{
			alarm(5);	
		      //////////////////////////////////////////////////////////////////////////

			if(flag_bloq_desploq == 0)
			{
				flag_bloq_desploq = 1;
				desbloquearSenal(&sigs);
			}
			else
			{
				flag_bloq_desploq = 0;
				bloquearSenal(&sigs);
			}	
			
			/* Esperar las señales */
			sigsuspend(&sigs);
			
		
			/* Señales pendientes */
			sigpending(&sigs);
		/*
			if(sigismember(&sigs, SIGINT) == 1)
			{
				printf("Hay una SIGINT Pendiente\n");
				sigfillset(&sigs);
				sigdelset(&sigs,SIGINT);
				sigsuspend(&sigs);
				printf("Ya la he atendido.\n");
			}
			else if(sigismember(&sigs, SIGUSR1) == 1)
			{
				printf("Hay una SIGUSR1 Pendiente\n");
				sigfillset(&sigs);
				sigdelset(&sigs,SIGUSR1);
				sigsuspend(&sigs);
				printf("Ya la he atendido.\n");
			}/*
			else if(sigismember(&sigs, SIGALRM) == 1)
			{
				printf("Hay una SIGALRM Pendiente\n");
				sigfillset(&sigs);
				sigdelset(&sigs,SIGALRM);
				sigsuspend(&sigs);
				printf("Ya la he atendido.\n");
			}*/
		/*	
			else if(sigismember(&sigs, SIGCHLD) == 1)
			{
				printf("Hay una SIGCHLD Pendiente\n");
				sigfillset(&sigs);
				sigdelset(&sigs,SIGCHLD);
				sigsuspend(&sigs);
				printf("Ya la he atendido.\n");
			}
			else
			{
				//printf("No hay señales pendientes.\n");
			}
			
			*/
			
		
		} // While
		
	}
	
	return 0;
}

/* -----------------------------------------------------------------*/
void hijo_tratamiento_senal(int signum)
{
	if(signum == SIGUSR1)
	{
		kill(getppid(),SIGUSR1);
		//printf("Soy hijo, la señal SIGUSR1 atendida.\n");
	}
	else if(signum == SIGUSR2)
	{
		//printf("Soy hijo, la señal SIGUSR2 atendida.\n");
		exit(10);
	}
}
void padre_tratamiento_senal(int signum)
{
	if(signum == SIGUSR1)
	{
		printf("MOSTRAR UN MENSAJE EN PANTALLA\n");
		//printf("Soy padre, la señal SIGUSR1 atendida.\n");
	}
	else if(signum == SIGINT)
	{
		kill(getpid(),SIGUSR1);
		//printf("Soy padre, la señal SIGINT atendida.\n");
	}
	else if(signum == SIGCHLD)
	{
		printf("El hijo ha muerto.\n");
		//printf("Soy padre, la señal SIGCHLD atendida.\n");
		wait(&estado);
		exit(0);
	}
	else if(signum == SIGALRM)
	{
		t2 = times(&bt2);
		printf("Tiempo de ejecución: ");
		//printf("%g s.\n", (float)(t2-t1)/ CLOCKS_PER_SEC);
		printf("%g s.\n", (float)(t2-t1)/100);
		
		
		
		
		//printf("Soy padre, la señal SIGALRM atendida.\n");
	}
	
}


/* ---------------------------------------------------- */
void desbloquearSenal(sigset_t *oldSet)
{
        sigset_t set;
        
        sigemptyset(&set);
        sigaddset(&set, SIGINT);
        sigaddset(&set, SIGUSR1);
        sigaddset(&set, SIGALRM);
        sigaddset(&set, SIGCHLD);
        
        sigprocmask(SIG_UNBLOCK, &set, oldSet);
	printf("He bloqueado todas las señales.\n");
}

void bloquearSenal(sigset_t *oldSet)
{
        sigprocmask(SIG_BLOCK, oldSet, NULL);
	printf("He desbloqueado todas las señales.\n");
}


